import json
import re
import time
from paho.mqtt import client as mqtt

from Ini_utils import UtilIni
from common_util import CommonUtil
from utils.logging_util import Log


class UtilText:
    def __init__(self, topic, receive_text, response_text):
        self.receive_text = receive_text
        self.response_text = response_text
        self.receive_topic = topic
        self.extract_text = {}
        self.reply_data = {}
        self.true_reply = []

    def util_receive(self):
        try:
            if isinstance(self.receive_text, dict):
                if check_text_relation(['dataBody', 'header'], self.receive_text.keys()):
                    for key, value in self.receive_text.items():
                        if key == 'dataBody':
                            if isinstance(value, dict):
                                for k, v in value.items():
                                    if k != "startTime":
                                        self.extract_text[k] = v
                                        if check_text_relation(k, "chgID"):
                                            UtilIni().writeln('AutoStation', 'chgID', v)
                                        elif check_text_relation(k, "rateModelID"):
                                            # 判断换电站还是充电站，费率id分开存，不会干扰
                                            if self.receive_text['header']['function'] == 'rateModeSetReq':
                                                UtilIni().writeln('AutoStation', 'spotRateModelID', v)
                                            else:
                                                UtilIni().writeln('AutoStation', 'rateModelID', v)
                                        elif check_text_relation(k, "chgDir"):
                                            self.extract_text['chgSwitch'] = int(v / 2)
                                            self.extract_text['startType'] = int(v * 2)
                                        elif check_text_relation(k, "orderSn"):
                                            UtilIni().writeln('AutoStation', 'orderSn', v)
                                            self.extract_text['swapSn'] = v
                                        elif k in ('plateNo', 'rfidCode', 'vin'):
                                            UtilIni().writeln('AutoStation', k, v)
                        elif key == 'header':
                            if isinstance(value, dict):
                                for k, v in value.items():
                                    if check_text_relation(k, 'index'):
                                        self.extract_text[k] = v
                                    if check_text_relation(v, 'chargeTypeSetReq'):
                                        if self.extract_text['ctrlType'] == 1:
                                            if self.extract_text['ctrlParam'] == 1:
                                                self.extract_text['startType'] = 1
                                            else:
                                                self.extract_text['startType'] = 2
                                        elif self.extract_text['ctrlType'] == 2:
                                            if self.extract_text['ctrlParam'] == 1:
                                                self.extract_text['chgSwitch'] = 0
                                            else:
                                                self.extract_text['chgSwitch'] = 1
                                    elif check_text_relation(v, 'remoteSwapStartReq'):
                                        self.extract_text['chgSwitch'] = 0
                                        self.extract_text['startType'] = 2
                                    elif check_text_relation(v, 'remoteChargeStopReq'):
                                        self.extract_text['chgState'] = 3
                                    elif check_text_relation(v, 'remoteChargeStartReq'):
                                        self.extract_text['chgState'] = 2

                return self.extract_text
        except Exception as e:
            Log().error(e)
            raise e

    def util_response(self):
        self.util_receive()
        for value in self.response_text:
            if isinstance(value, dict):
                if 'oppositeFunction' in value.keys():
                    if check_text_relation((extract_value_by_key(self.receive_text, "function")),
                                           extract_value_by_key(value, 'oppositeFunction')[0]):
                        Log().info(f'Find reply message name ：===={value["name"]}====')
                        value['payload']['dataBody'] = replace_response_data(self.extract_text,
                                                                             value['payload']['dataBody'])
                        value['payload']['header'] = replace_response_data(self.extract_text,
                                                                           value['payload']['header'])
                        value["payload"] = replace_load(value["payload"])
                        if check_text_relation(extract_value_by_key(value['payload'], "function"), 'chargerState'):
                            for context in value['payload']['dataBody']:
                                if self.extract_text['chgID'] in json.dumps(context):
                                    replace_response_data(self.extract_text, context)
                                    for text in context['gunList']:
                                        if 'chgState' in self.extract_text.keys():
                                            text["chgState"] = self.extract_text['chgState']
                        receive_topic_item = self.util_topic(self.receive_topic)
                        response_topic = f"{receive_topic_item[0]}/{receive_topic_item[1]}/{value['direction']}/{value['type']}"
                        self.reply_data[response_topic] = value['payload']
                        publish(topic=response_topic, payload=value['payload'])
                        Log().info(
                            f'Reply message is：{response_topic},{json.dumps(value["payload"], ensure_ascii=False)})\n')
                        time.sleep(1)

    def util_topic(self, topic):
        return str(topic).split('/')


def check_text_relation(response, receive):
    if isinstance(response, list):
        return all(item in receive for item in response) or response == receive
    if isinstance(receive, list):
        return response in receive
    return response == receive


def extract_value_by_key(context, target_key):
    """
    通过key获取value的值
    :param target_key:
    :return:
    """
    if isinstance(context, dict):
        pattern = re.compile(fr'"{target_key}"\s*:\s*(\[[^\[\]]*]|{{[^}}]*}}|"[^"]*"|\S+)', re.MULTILINE)
        matches = re.finditer(pattern, json.dumps(context))
        values = []
        for match in matches:
            value = match.group(1).strip('"')
            values.append(value)
        return values


def replace_response_data(receive_data, response_data):
    def replace_dict_values(receive_dict, response_dict):
        for key, value in receive_dict.items():
            if key in response_dict:
                if isinstance(value, dict) and isinstance(response_dict[key], dict):
                    replace_dict_values(value, response_dict[key])
                else:
                    response_dict[key] = value

    replace_dict_values(receive_data, response_data)

    return response_data


def publish(topic, payload):
    host = UtilIni().getvalue('AutoStation', 'ip')
    port = UtilIni().getvalue('AutoStation', 'port')
    mqttClient = mqtt.Client(protocol=3)
    mqttClient.username_pw_set("admin", "veZgHjmY")  # mqtt服务器账号密码
    mqttClient.connect(host=host, port=int(port),
                       keepalive=60)
    mqttClient.publish(topic=topic, payload=json.dumps(payload, ensure_ascii=False), qos=2)
    time.sleep(2)


def replace_load(data):
    if data and isinstance(data, dict):
        str_data = json.dumps(data)
    else:
        str_data = data
    for a in range(1, str_data.count("$(") + 1):
        if "$(" in str_data and ")" in str_data:
            start_index = str_data.index("$(")
            end_index = str_data.index(")")
            old_value = str_data[start_index:end_index + 1]
            func_name = old_value[2:old_value.index(')')]
            new_value_func = getattr(CommonUtil, str(func_name))
            new_value = new_value_func()
            str_data = str_data.replace(old_value, new_value)
    # 还原数据类型
    if data and isinstance(data, dict):
        data = json.loads(str_data)
    else:
        data = str_data
    return data


def get_payload(payload, function):
    for value in payload:
        for v in value.values():
            if v == function:
                return value['payload']
